home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / stktrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-18  |  5.6 KB  |  258 lines

  1. /* This file contains code to print function/arg stack tracebacks
  2.  * at run time, which is extremely useful for finding heap free() errors.
  3.  *
  4.  * This code is highly specific to Borland C and the 80x6 machines.
  5.  *
  6.  * April 10, 1992 P. Karn
  7.  * (adopted for 911229 based code by Johan, WG7J)
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <dos.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #include "global.h"
  16. #include "config.h"
  17. #include "proc.h"
  18.  
  19. #ifdef STKTRACE
  20.  
  21. struct symtab {
  22.     struct symtab *next;
  23.     unsigned short seg;
  24.     unsigned short offs;
  25.     char *name;
  26. };
  27. static struct symtab *Symtab;
  28. static void rdsymtab __ARGS((int unused,void *name,void *p));
  29. static void clrsymtab __ARGS((void));
  30. static struct symtab *findsym __ARGS((void (*)()));
  31. static int scompare();
  32. static void paddr __ARGS((void (*pc)(),FILE *fp));
  33.  
  34. static unsigned short Codeseg;
  35.  
  36. void
  37. stktrace()
  38. {
  39.     int i,j;
  40.     unsigned short far *context;
  41.     unsigned short far *cnext;
  42.     unsigned short far *ctmp;
  43.     void (*pc)();
  44.     int nargs;
  45.     struct proc *rdproc;
  46.     struct symtab *sp;
  47.     extern char **_argv;
  48.     char *mapname;
  49.     char *cp;
  50.     FILE *fp;
  51.     time_t t;
  52.  
  53.     /* output to file */
  54.     if((fp = fopen("stktrace.out","at")) == NULLFILE)
  55.         return;    /* Give up */
  56.  
  57.     time(&t);
  58.     fprintf(fp,"stktrace from proc %s at %s",Curproc->name,ctime(&t));
  59.     Codeseg = _psp + 0x10;
  60. #ifdef    notdef
  61.     fprintf(fp,"Code base segment: %x\n",Codeseg);
  62. #endif
  63.     /* Construct name of map file */
  64.     mapname = malloc(strlen(_argv[0]) + 5);
  65.     strcpy(mapname,_argv[0]);
  66.     if((cp = strrchr(mapname,'.')) != NULLCHAR)
  67.         *cp = '\0';
  68.     strcat(mapname,".map");
  69.     printf ("Mapname=%s\n", mapname);
  70.  
  71.     /* Read the symbol table in another process to avoid overstressing
  72.      * the stack in this one
  73.      */
  74.     rdproc = newproc("rdsymtab",512,rdsymtab,1,mapname,NULL,0);
  75.     pwait(rdproc);
  76.     free(mapname);
  77.  
  78.     context = MK_FP(_SS,_BP);
  79.     pc = stktrace;
  80.  
  81.     for(i=0;i<20;i++){
  82.         paddr(pc,fp);
  83.         sp = findsym(pc);
  84.         if(sp != NULL)
  85.             fprintf(fp," %s+%x",sp->name,FP_OFF(pc) - sp->offs);
  86.  
  87.         if(FP_OFF(context) == 0){
  88.             /* No context left, we're done */
  89.             fputc('\n',fp);
  90.             break;
  91.         }
  92.         cnext = MK_FP(FP_SEG(context),*context);
  93.         /* Compute number of args to display */
  94.         if(FP_OFF(cnext) != 0){
  95.             nargs = cnext - context - (1 + sizeof(pc)/2);
  96.             if(nargs > 20)
  97.                 nargs = 20; /* limit to reasonable number */
  98.         } else {
  99.             /* No higher level context, so just print an
  100.              * arbitrary fixed number of args
  101.              */
  102.             nargs = 6;
  103.         }        
  104.         /* Args start after saved BP and return address */
  105.         ctmp = context + 1 + sizeof(pc)/2;
  106.         fputc('(',fp);
  107.         for(j=0;j<nargs;j++){
  108.             fprintf(fp,"%x",*ctmp);
  109.             if(j < nargs-1)
  110.                 fputc(' ',fp);
  111.             else
  112.                 break;
  113.             ctmp++;
  114.         }
  115.         fprintf(fp,")\n");
  116. #ifdef    notdef
  117.         if(strcmp(cp,"_main") == 0)
  118.             break;
  119. #endif
  120.  
  121. #ifdef    LARGECODE
  122.         pc = MK_FP(context[2],context[1]);
  123. #else
  124.         pc = (void (*)())MK_FP(FP_SEG(pc),context[1]);
  125. #endif
  126.         context = cnext;
  127.     }
  128.     clrsymtab();
  129.     fclose(fp);
  130. }
  131. static struct symtab *
  132. findsym(pc)
  133. void (*pc)();
  134. {
  135.     struct symtab *sp,*spprev;
  136.     unsigned short seg,offs;
  137.     
  138. #ifdef    LARGECODE
  139.     seg = FP_SEG(pc) - Codeseg;
  140. #else
  141.     seg = 0;    /* Small code, no segment */
  142. #endif
  143.     offs = FP_OFF(pc);
  144.     spprev = NULL;
  145.     for(sp = Symtab;sp != NULL;spprev = sp,sp = sp->next){
  146.         if(sp->seg > seg || (sp->seg == seg && sp->offs > offs)){
  147.             break;
  148.         }
  149.     }
  150.     return spprev;
  151. }
  152. static void
  153. clrsymtab()
  154. {
  155.     struct symtab *sp,*spnext;
  156.  
  157.     for(sp = Symtab;sp != NULL;sp = spnext){
  158.         spnext = sp->next;
  159.         free(sp->name);
  160.         free(sp);
  161.     }
  162.     Symtab = NULL;
  163. }
  164. static void
  165. rdsymtab(unused,name,p)
  166. int unused;
  167. void *name;
  168. void *p;
  169. {
  170.     char *buf;
  171.     FILE *fp;
  172.     unsigned short seg;
  173.     unsigned short offs;
  174.     struct symtab *sp;
  175.     struct symtab **spp;
  176.     int size = 0;
  177.     int i;
  178.  
  179.     if((fp = fopen(name,"rt")) == NULL){
  180.         printf("Stktrace: can't read %s\n",name);
  181.         return;
  182.     }
  183.     buf = (char *)malloc(128);
  184.     while(fgets(buf,128,fp),!feof(fp)){
  185.         rip(buf);
  186.         if(strcmp(buf,"  Address         Publics by Value") == 0)
  187.             break;
  188.     }
  189.     if(feof(fp)){
  190.         printf("Stktrace: Can't find header line in %s\n",name);
  191.         free(buf);
  192.         return;
  193.     }
  194.     Symtab = NULL;
  195.     while(fgets(buf,128,fp),!feof(fp)){
  196.         rip(buf);
  197.         if(sscanf(buf,"%x:%x",&seg,&offs) != 2)
  198.             continue;
  199.         sp = (struct symtab *)malloc(sizeof(struct symtab));
  200.         sp->offs = offs;
  201.         sp->seg = seg;
  202.         sp->name = strdup(buf+17);
  203.         sp->next = Symtab;
  204.         Symtab = sp;
  205.         size++;
  206.     }
  207.     fclose(fp);
  208.     free(buf);
  209. #ifdef    notdef
  210.     printf("Stktrace: Symbols read: %d\n",size);
  211. #endif
  212.     /* Sort the symbols using the quicksort library function */
  213.     spp = malloc(size*sizeof(struct symtab *));
  214.     for(i=0,sp = Symtab;sp != NULL;i++,sp = sp->next)
  215.         spp[i] = sp;
  216.     qsort(spp,size,sizeof(struct symtab *),scompare);
  217.     /* Now put them back in the linked list */
  218.     Symtab = NULL;
  219.     for(i=size-1;i >= 0;i--){
  220.         sp = spp[i];
  221.         sp->next = Symtab;
  222.         Symtab = sp;
  223.     }
  224.     free(spp);
  225. #ifdef    notdef
  226.     for(sp = Symtab;sp != NULL;sp = sp->next)
  227.         printf("Stktrace: %x:%x   %s\n",sp->seg,sp->offs,sp->name);
  228. #endif
  229. }
  230. static int
  231. scompare(a,b)
  232. struct symtab **a,**b;
  233. {
  234.     if((*a)->seg > (*b)->seg)
  235.         return 1;
  236.     if((*a)->seg < (*b)->seg)
  237.         return -1;
  238.     if((*a)->offs > (*b)->offs)
  239.         return 1;
  240.     if((*a)->offs < (*b)->offs)
  241.         return -1;
  242.     return 0;
  243. }
  244. /* Print a code address according to the memory model */
  245. static void
  246. paddr(pc,fp)
  247. void (*pc)();
  248. FILE *fp;
  249. {
  250. #ifdef    LARGECODE
  251.     fprintf(fp,"%04x:%04x",FP_SEG(pc) - Codeseg,FP_OFF(pc));
  252. #else
  253.     fprintf(fp,"%04x",FP_OFF(pc));
  254. #endif    
  255. }
  256.  
  257. #endif /* STKTRACE */
  258.